import axios from 'axios';
import { getAccessToken, getTenantId } from '@/utils/auth';
import pinyin from 'js-pinyin';
import { useEnv } from '@/hooks/useEnv';

/**
 *
 * @param component 需要注册的组件
 * @param alias 组件别名
 * @returns any
 */
export const withInstall = <T>(component: T, alias?: string) => {
	const comp = component as any;
	comp.install = (app: any) => {
		app.component(comp.name || comp.displayName, component);
		if (alias) {
			app.config.globalProperties[alias] = component;
		}
	};
	return component as T & Plugin;
};

/**
 * @param str 需要转下划线的驼峰字符串
 * @returns 字符串下划线
 */
export const humpToUnderline = (str: string): string => {
	return str.replace(/([A-Z])/g, '-$1').toLowerCase();
};

/**
 * @param str 需要转驼峰的下划线字符串
 * @returns 字符串驼峰
 */
export const underlineToHump = (str: string): string => {
	if (!str) return '';
	return str.replace(/\-(\w)/g, (_, letter: string) => {
		return letter.toUpperCase();
	});
};

export const setCssVar = (prop: string, val: any, dom = document.documentElement) => {
	dom.style.setProperty(prop, val);
};

/**
 * 查找数组对象的某个下标
 * @param {Array} ary 查找的数组
 * @param {Functon} fn 判断的方法
 */

export const findIndex = <T = Recordable>(ary: Array<T>, fn: any): number => {
	if (ary.findIndex) {
		return ary.findIndex(fn);
	}
	let index = -1;
	ary.some((item: T, i: number, ary: Array<T>) => {
		const ret: T = fn(item, i, ary);
		if (ret) {
			index = i;
			return ret;
		}
	});
	return index;
};

export const trim = (str: string) => {
	return str.replace(/(^\s*)|(\s*$)/g, '');
};

/**
 * @param {Date | number | string} time 需要转换的时间
 * @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
 */
export const formatTime = (time: Date | number | string, fmt: string) => {
	if (!time) return '';
	else {
		const date = new Date(time);
		const o:any = {
			'M+': date.getMonth() + 1,
			'd+': date.getDate(),
			'H+': date.getHours(),
			'm+': date.getMinutes(),
			's+': date.getSeconds(),
			'q+': Math.floor((date.getMonth() + 3) / 3),
			S: date.getMilliseconds()
		};
		if (/(y+)/.test(fmt)) {
			fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
		}
		for (const k in o) {
			if (new RegExp('(' + k + ')').test(fmt)) {
				fmt = fmt.replace(
					RegExp.$1,
					RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
				);
			}
		}
		return fmt;
	}
};

/**
 * 生成随机字符串
 */
export const toAnyString = () => {
	const str: string = 'xxxxx-xxxxx-4xxxx-yxxxx-xxxxx'.replace(/[xy]/g, (c: string) => {
		const r: number = (Math.random() * 16) | 0;
		const v: number = c === 'x' ? r : (r & 0x3) | 0x8;
		return v.toString();
	});
	return str;
};

export const generateUUID = () => {
	if (typeof crypto === 'object') {
		if (typeof crypto.randomUUID === 'function') {
			return crypto.randomUUID();
		}
		if (typeof crypto.getRandomValues === 'function' && typeof Uint8Array === 'function') {
			const callback = (c: any) => {
				const num = Number(c);
				return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(
					16
				);
			};
			return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, callback);
		}
	}
	let timestamp = new Date().getTime();
	let performanceNow =
		(typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0;
	return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
		let random = Math.random() * 16;
		if (timestamp > 0) {
			random = (timestamp + random) % 16 | 0;
			timestamp = Math.floor(timestamp / 16);
		} else {
			random = (performanceNow + random) % 16 | 0;
			performanceNow = Math.floor(performanceNow / 16);
		}
		return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16);
	});
};

/**
 * element plus 的文件大小 Formatter 实现
 *
 * @param row 行数据
 * @param column 字段
 * @param cellValue 字段值
 */
export const fileSizeFormatter = (row: any, column: any, cellValue: any) => {
	const fileSize = cellValue;
	const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
	const srcSize = parseFloat(fileSize);
	const index = Math.floor(Math.log(srcSize) / Math.log(1024));
	const size = srcSize / Math.pow(1024, index);
	const sizeStr = size.toFixed(2); //保留的小数位数
	return sizeStr + ' ' + unitArr[index];
};

/**
 * 将值复制到目标对象，且以目标对象属性为准，例：target: {a:1} source:{a:2,b:3} 结果为：{a:2}
 * @param target 目标对象
 * @param source 源对象
 */
export const copyValueToTarget = (target: any, source: any) => {
	const newObj = Object.assign({}, target, source);
	// 删除多余属性
	Object.keys(newObj).forEach((key) => {
		// 如果不是target中的属性则删除
		if (Object.keys(target).indexOf(key) === -1) {
			delete newObj[key];
		}
	});
	// 更新目标对象值
	Object.assign(target, newObj);
};

// TODO @puhui999：返回要带上 .00 哈.例如说 1.00
/**
 * 将一个整数转换为分数保留两位小数
 * @param num
 */
export const formatToFraction = (num: number | string | undefined): number => {
	if (typeof num === 'undefined') return 0;
	const parsedNumber = typeof num === 'string' ? parseFloat(num) : num;
	return parseFloat((parsedNumber / 100).toFixed(2));
};

/**
 * 将一个分数转换为整数
 * @param num
 */
export const convertToInteger = (num: number | string | undefined): number => {
	if (typeof num === 'undefined') return 0;
	const parsedNumber = typeof num === 'string' ? parseFloat(num) : num;
	// TODO 分转元后还有小数则四舍五入
	return Math.round(parsedNumber * 100);
};

/**
 * 将一个数转换为 1.00 这样
 * 数据呈现的时候使用
 *
 * @param num 整数
 */
export const floatToFixed2 = (num: number | string | undefined): string => {
	let str = '0.00';
	if (typeof num === 'undefined') {
		return str;
	}
	const f = formatToFraction(num);
	const decimalPart = f.toString().split('.')[1];
	const len = decimalPart ? decimalPart.length : 0;
	switch (len) {
		case 0:
			str = f.toString() + '.00';
			break;
		case 1:
			str = f.toString() + '0';
			break;
		case 2:
			str = f.toString();
			break;
	}
	return str;
};

/**
 * 元转分
 */
export const yuanToFen = (amount: string | number): number => {
	return Math.round(Number(amount) * 100);
};

/**
 * 分转元
 */
export const fenToYuan = (amount: string | number): number => {
	return Number((Number(amount) / 100).toFixed(2));
};

// 防抖: 只执行最后一次, 定时器内触发则重新计时
export const debounceDirective = {
	beforeMount(el: any, binding: any) {
		let timer: any;
		const { arg, value: { fn, time, keys, params } } = binding;
		el.addEventListener(arg || "input", () => {
			clearTimeout(timer);
			timer = setTimeout(() => {
				fn(keys, params);
			}, time || 600); // 600毫秒防抖延迟，可以根据需求调整
		});
	},
};

// // 节流: 控制执行次数, 定时器结束才会再次触发
// export const throttleDirective: Directive<HTMLElement, (...args: any[]) => void> = {
// 	mounted(el, binding) {
// 		let timeout = null;
// 		const handler = () => {
// 			if (timeout) return;
// 			binding.value();
// 			timeout = setTimeout(() => {
// 				timeout = null;
// 			}, 500); // 节流时间，可以作为参数传递
// 		};

// 		el.addEventListener('click', handler);
// 	},
// 	beforeUnmount(el) {
// 		el.removeEventListener('click', el._v_throttleHandler);
// 	}
// };

// 日期转时间戳
export const getTimestamp = (value: any) => {
	return new Date(value).getTime() / 1000;
};

// 获取当前时间
export const getCurrentDate = () => {
	const date = new Date();
	const year = date.getFullYear() + '';
	const month = date.getMonth() + 1 < 10 ? `0${date.getMonth() + 1}` : date.getMonth() + 1;
	const day = date.getDate() < 10 ? `0${date.getDate()}` : date.getDate();
	const h = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours();
	const m = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes();
	const s = date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds();
	return `${year}-${month}-${day} ${h}:${m}:${s}`;
};

// 判断某个字符出现过几次
export const getCountSymbol = (symbol: any, str: string) => {
	// 使用正则表达式，'g'标志表示全局匹配
	const regex = new RegExp(symbol, 'g');
	// match()方法返回所有匹配的数组，数组长度即为出现次数
	return (str.match(regex) || []).length;
};

// a标签下载文件
export const downFile = async (fileUrl: string, fileName: string) => {
	try {
		// 使用 fetch API 下载文件
		const response = await fetch(fileUrl);
		const blob = await response.blob();
		const url = URL.createObjectURL(blob);
		const link = document.createElement('a');
		link.href = url;
		// 文件名和后缀
		link.download = `${fileName}`;
		// 将 <a> 标签添加到页面中并模拟点击下载
		document.body.appendChild(link);
		link.click();
		// 下载完成后移除 <a> 标签和 URL 对象
		document.body.removeChild(link);
		URL.revokeObjectURL(url);
	} catch (error) {
		console.error('Error downloading the file:', error);
	}
};

// 千分位
export const formatNumber = (value: any) => {
	if (!value) return;
	// 将数字转换为带有两位小数的格式
	const formattedValue = Number(value).toFixed(2);
	// 使用正则表达式添加千分位分隔符
	return formattedValue.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

// 判断两个对象除了特定值以外，是否都一样
export const isSame = (obj1: any, obj2: any, field: any) => {
	if(!obj1 || !obj2) return;
	// 获取两个对象的键
	const keys1 = Object.keys(obj1).filter((key) => key !== field);
	const keys2 = Object.keys(obj2).filter((key) => key !== field);

	// 比较键的数量
	if (keys1.length !== keys2.length) {
		return false;
	}

	// 比较键的值
	for (const key of keys1) {
		if (obj1[key] !== obj2[key]) {
			// 如果是数组
			if(obj1[key] instanceof Array){
				return	obj1[key].every((item, index) => item === obj1[key][index]);
			}
			else {
				return false;
			}

		}
	}

	return true;
};

export const getDateDiff = (targetDate: any) => {
	const now = Date.now(); // 当前时间的时间戳（毫秒）
	const diff = now - new Date(targetDate).getTime(); // 时间差（毫秒）

	// 转换为秒、分钟、小时、天数
	const seconds = Math.floor(diff / 1000);
	const minutes = Math.floor(diff / (1000 * 60));
	const hours = Math.floor(diff / (1000 * 60 * 60));
	const days = Math.floor(diff / (1000 * 60 * 60 * 24));
	const month = Math.floor(diff / (1000 * 60 * 60 * 24 * 30));
	const years = Math.floor(diff / (1000 * 60 * 60 * 24 * 30 * 12));

	if (seconds < 60) return `刚刚`;
	if (minutes < 60) return `${minutes}分钟前`;
	if (hours < 24) return `${hours}小时前`;
	if (month < 12) return `${month}个月前`;
	if (years < 12) return `${years}年前`;
	return `${days} 天前`;
};


// 把十六进制颜色代码转换为RGBA格式
export const hexToRgba = (hex='#165DFF', opacity = 0.3) => {
    hex = hex ? hex :'#165DFF'
    return "rgba(" + parseInt("0x" + hex.slice(1, 3)) + "," + parseInt("0x" + hex.slice(3, 5)) + "," + parseInt("0x" + hex.slice(5, 7)) + "," + opacity + ")"
}

export function formatAmount(amount: any, currencySymbol = "¥", unitType = "") {
	let formattedAmount;
	let unitSuffix = "";

	switch (unitType) {
		case "K":
			formattedAmount = amount / 1000;
			unitSuffix = "K";
			break;
		case "W":
			formattedAmount = amount / 10000;
			unitSuffix = "W";
			break;
		case "SW":
			formattedAmount = amount / 100000;
			unitSuffix = "SW";
			break;
		case "M":
			formattedAmount = amount / 1000000;
			unitSuffix = "M";
			break;
		case "E":
			formattedAmount = amount / 100000000;
			unitSuffix = "E";
			break;
		default:
			formattedAmount = amount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
			break;
	}

	return `${currencySymbol}${formattedAmount}${unitSuffix}`;
}

export function formatPhone(phone: string, separator = "-") {
	if (!phone) return "";
	const formatted = phone.replace(/(\d{3})(\d{4})(\d{4})/, `$1${separator}$2${separator}$3`);
	return formatted;
}

export const formatMoney = (num: any, decimal = 2, split = ",", pre = "¥", next = "") => {
	/*
		parameter：
		num：格式化目标数字
		decimal：保留几位小数，默认2位
		split：千分位分隔符，默认为,
		moneyFormat(123456789.87654321, 2, ',') // 123,456,789.88
	*/
	if (isFinite(num) && num != null) {
		// num是数字
		if (num === 0) {
			// 为0
			return pre + num.toFixed(decimal) + next;
		} else {
			// 非0
			let res = "";
			const dotIndex = String(num).indexOf(".");
			if (dotIndex === -1) {
				// 整数
				if (decimal === 0) {
					res = String(num).replace(/(\d)(?=(?:\d{3})+$)/g, `$1${split}`);
				} else {
					res = String(num).replace(/(\d)(?=(?:\d{3})+$)/g, `$1${split}`) + "." + "0".repeat(decimal);
				}
			} else {
				// 非整数
				// js四舍五入 Math.round()：正数时4舍5入，负数时5舍6入
				// Math.round(1.5) = 2
				// Math.round(-1.5) = -1
				// Math.round(-1.6) = -2
				// 保留decimals位小数
				const numStr = String((Math.round(num * Math.pow(10, decimal)) / Math.pow(10, decimal)).toFixed(decimal)); // 四舍五入，然后固定保留2位小数
				const decimals = numStr.slice(dotIndex, dotIndex + decimal + 1); // 截取小数位
				res = String(numStr.slice(0, dotIndex)).replace(/(\d)(?=(?:\d{3})+$)/g, `$1${split}`) + decimals;
			}
			return pre + res + next;
		}
	} else {
		return "--";
	}
};

// 日期，是否显示时分秒，切换显示年月日
export function formatDate(date: Date | string, showTime: boolean = false, formatType: string = "yearMonthDay"): string {
    if (!date) return '--';

    // 处理字符串日期
    if (typeof date === 'string') {
        if (/^\d{4}$/.test(date)) { // 匹配年份格式如 "2024"
            date = new Date(parseInt(date), 0, 1); // 设置为该年的1月1日
        } else if (/^\d{4}-\d{2}$/.test(date)) { // 匹配年月格式如 "2024-10"
            const [year, month] = date.split('-').map(Number);
            date = new Date(year, month - 1, 1); // 设置为该年的指定月的1日
        } else {
            date = new Date(date); // 尝试直接转换为Date对象
        }
    }

    if (!(date instanceof Date) || isNaN(date.getTime())) return '--'; // 验证日期对象是否有效

    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");
    const seconds = String(date.getSeconds()).padStart(2, "0");

    let formattedDate = "";

    switch (formatType) {
        case "year":
            formattedDate = `${year}`;
            break;
        case "month":
            formattedDate = `${year}/${month}`;
            break;
        default:
            formattedDate = `${year}/${month}/${day}`;
            break;
    }

    if (showTime) {
        formattedDate += ` ${hours}:${minutes}:${seconds}`;
    }

    return formattedDate;
}



export const isValid = (value: any) => {
    return value !== null && value !== '' && value !== undefined
}

// 创建并触发自定义事件
export const sendMessage = (data: any) => {
    const event = new CustomEvent('receiveMessage', { detail: data });
    window.dispatchEvent(event);
}

export function SelectInfo(list: any, value: any, labelKey = "label", valueKey = "value") {
	if (!Array.isArray(list)) return "";
	if (value === "") return "";
	const door = list.find((i) => i[valueKey] == value);
	return door ? door[labelKey] : "";
}

// export const treeData = computed(() => {
// 	if (!filterText.value) return computedList.value;
// 	return searchData(filterText.value);
// })

// export const treeData = () => {

// }

//  function searchData(keyword) {
// 	const loop = (data) => {
// 		const result = [];
// 		data.forEach(item => {
// 			if (item.name.toLowerCase().indexOf(keyword.toLowerCase()) > -1) {
// 				result.push({...item});
// 			} else if (item.children) {
// 				const filterData = loop(item.children);
// 				if (filterData.length) {
// 					result.push({
// 						...item,
// 						children: filterData
// 					})
// 				}
// 			}
// 		})
// 		return result;
// 	}
// 	return loop(computedList.value);
// }

// 二进制转 blob
export const fileToBlob = async (id: number, name: string) => {
    const headers = {
        terminal: 20,
        tenantId: getTenantId(),
        version: import.meta.env.VITE_APP_VERSION,
        Authorization: 'Bearer ' + getAccessToken(),
    }
    try {
        // 发送请求，设置响应类型为 blob
        const response = await axios.get(`${useEnv('VITE_API_URL') + `/oss/file/${id}/get`}`, {
            responseType: 'blob',
            headers: {...headers}
        });
        const contentType = response.headers['content-type'];
        const blob = new Blob([response.data], {type: contentType});
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = name;
        link.click();
        window.URL.revokeObjectURL(url);
    } catch (error) {
        console.error('下载文件出错:', error);
    }
}

// 根据中文获取首字母
export const getPinYin = (str: string) => {
	pinyin.setOptions({ checkPolyphone: false, charCase: 2 });
	return str ? pinyin.getCamelChars(str).slice(0, 1) : '-';
}

/**
 * 将时间转换为 `几秒前`、`几分钟前`、`几小时前`、`几天前`
 * @param param 当前时间，new Date() 格式或者字符串时间格式
 * @param format 需要转换的时间格式字符串
 * @description param 10秒：  10 * 1000
 * @description param 1分：   60 * 1000
 * @description param 1小时： 60 * 60 * 1000
 * @description param 24小时：60 * 60 * 24 * 1000
 * @description param 3天：   60 * 60* 24 * 1000 * 3
 * @returns 返回拼接后的时间字符串
 */
export function formatChatTime(timestamp: any, type: boolean = false): string {
	const now = new Date();
	const messageDate = new Date(timestamp);

	const currentYear = now.getFullYear();
	const messageYear = messageDate.getFullYear();
	const currentMonth = now.getMonth();
	const messageMonth = messageDate.getMonth();
	const currentDay = now.getDate();
	const messageDay = messageDate.getDate();

	if (messageYear === currentYear && messageMonth === currentMonth && messageDay === currentDay) {
	  return `${messageDate.getHours()}:${messageDate.getMinutes() < 10 ? `0${messageDate.getMinutes()}` : messageDate.getMinutes()}`;
	} else if (messageYear === currentYear && messageDay === currentDay - 1) {
	  return `昨天 ${messageDate.getHours()}:${messageDate.getMinutes() < 10 ? `0${messageDate.getMinutes()}` : messageDate.getMinutes()}`;
	} else if (messageYear === currentYear) {
	  return `${messageDate.getMonth() + 1}/${messageDate.getDate()}
	  ${ type ? ` ${messageDate.getHours() < 10 ? `0${messageDate.getHours()}` : messageDate.getHours() }:${messageDate.getMinutes() < 10 ? `0${messageDate.getMinutes()}` : messageDate.getMinutes()}` : '' }`;
	} else {
	  return `${messageDate.getFullYear()}/${messageDate.getMonth() + 1}/${messageDate.getDate()}`;
	}
}

// 截图-创建img
export const createElementImg = (e: any, vnode: any, w = 200, h = 0) => {
	const img = document.createElement("img");
	img.src = e;
	img.alt = "图片加载失败";
	img.width = w;
	if (h) {
		img.height = h;
	}
	vnode.appendChild(img);
};

// 取文件大小单位
export const getFileUnit = (bytes: any) => {
	const size = +bytes;
	if (size < 1000) {
        return size + ' B';
    } else if (size < 1000 * 1000) {
        return (size / 1000).toFixed(2) + ' KB';
    } else {
        return (size / (1000 * 1000)).toFixed(2) + ' MB';
    }
}

// 根据地址判断文件类型
export const getFileType = (url: string) => {
	const lastIndex = url?.lastIndexOf('.');
	let types:any = '';
	if (lastIndex!== -1) {
		const extension = url.slice(lastIndex + 1).toLowerCase();
		if (['bmp', 'jpg', 'jpeg', 'png', 'tif', 'gif', 'pcx', 'tga', 'exif', 'fpx', 'svg', 'psd', 'cdr', 'pcd', 'dxf', 'ufo', 'eps', 'ai', 'raw', 'WMF', 'avif', 'apng'].includes(extension)) {
			types = 'img';
		} else if (['3gp', 'avi', 'mp4', 'mkv', 'flv', 'wmv', 'mov', 'rmvb', 'rm', 'm4v', 'asf', 'vob', 'ogv', 'webm', 'mxf', 'divx', 'xvid', 'dv', 'h264', 'h265', 'ts', 'mpeg', 'mpe', 'mpg', 'm2v', 'm3u8'].includes(extension)) {
			types = 'video';
		} else {
			types = 'file';
		}
	} else {
		types = null;
	}
	return types;
}

// 取文件名
export const getFileName = (fileName: string) => {
	// 找到最后一个点的索引
	const lastDotIndex = fileName?.lastIndexOf('.');
	// 如果存在点，则提取最后一个点之前的部分作为文件名
	if (lastDotIndex!== -1) {
		return fileName?.substring(0, lastDotIndex);
	} else {
		return fileName;
	}
}
